package ch.zbw.timeline.service;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Time;
import java.util.Calendar;
import java.util.List;

import org.apache.log4j.Logger;

import ch.zbw.timeline.domain.Allocation;
import ch.zbw.timeline.domain.DailyPresence;
import ch.zbw.timeline.domain.Employee;
import ch.zbw.timeline.domain.Entry;
import ch.zbw.timeline.domain.HolidayFormula;
import ch.zbw.timeline.domain.LogEntry;
import ch.zbw.timeline.domain.OverTimePool;
import ch.zbw.timeline.domain.Period;
import ch.zbw.timeline.domain.Process;
import ch.zbw.timeline.domain.Role;
import ch.zbw.timeline.domain.Statistic;
import ch.zbw.timeline.domain.Task;
import ch.zbw.timeline.domain.YearConfig;
import ch.zbw.timeline.repository.RoleRepository;
import ch.zbw.timeline.repository.hibernate.HibernateRoleRepository;

/**
 * Handels the communication over Java RMI
 * 
 * @author Daniel Stefanovic
 * @version 19.01.2012
 * 
 */
public class RmiServerService extends UnicastRemoteObject implements
		ServerService {

	private final static Logger LOGGER = Logger
			.getLogger(RmiServerService.class);
	private final static String SERVER_NAME = "timeline-server";

	private EmployeeService employeeService = new ZbwEmployeeService();
	private DailyPresenceService dailyPresenceService = new ZbwDailyPresenceService();
	private EntryService entryService = new ZbwEntryService();
	private RoleRepository roleRepository = new HibernateRoleRepository();
	private SecurityService securityService = new ZbwSecurityService();
	private TaskProcessAllocationService taskProcessAllocationService = new ZbwTaskProcessAllocationService();
	private OverTimePoolService overTimePoolService = new ZbwOverTimePoolService();
	private LogService logService = new ZbwLogService();
	private YearConfigService yearConfigService = new ZbwYearConfigService();
	private HolidayService holidayService = new ZbwHolidayService();
	private StatisticService statisticService = new ZbwStatisticService();

	/**
	 * Constructor (is required)
	 * 
	 * @throws RemoteException
	 */
	public RmiServerService() throws RemoteException {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#startServer()
	 */
	@Override
	public void startServer() {
		try {
			LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
			Naming.rebind(SERVER_NAME, this);
		} catch (RemoteException e) {
			LOGGER.error("Fehler bei der Erstellung des Registry-Eintrages: "
					+ e.getMessage());
		} catch (MalformedURLException e) {
			LOGGER.error("Fehler beim Einbinden der URL zu einem Remote-Objekt: "
					+ e.getMessage());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#connectToServer(java.lang.String)
	 */
	@Override
	public ServerService connectToServer(String url) throws Exception {
		return (ServerService) Naming.lookup(url + SERVER_NAME);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllRoles()
	 */
	@Override
	public List<Role> getAllRoles() throws RemoteException {
		return roleRepository.getAllRoles();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#authenticate(java.lang.String,
	 * java.lang.String, ch.zbw.timeline.domain.Role)
	 */
	@Override
	public Employee authenticate(String userName, String password, Role role)
			throws RemoteException {
		return employeeService.authenticate(userName, password, role);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#getDailyPresence(ch.zbw.timeline
	 * .domain.Employee, java.util.Calendar)
	 */
	@Override
	public DailyPresence getDailyPresence(Employee employee, Calendar day)
			throws RemoteException {
		return dailyPresenceService.getDailyPresence(employee, day);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#getAllEntries(ch.zbw.timeline.domain
	 * .DailyPresence)
	 */
	@Override
	public List<Entry> getAllEntries(DailyPresence presence) {
		return entryService.getAllEntries(presence);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#createEntry(ch.zbw.timeline.domain
	 * .DailyPresence, double, ch.zbw.timeline.domain.Allocation,
	 * java.lang.String, ch.zbw.timeline.domain.OverTimePool)
	 */
	@Override
	public Entry createEntry(DailyPresence dailyPresence, double duration,
			Allocation allocation, String comment, OverTimePool overTimePool) {
		return entryService.createEntry(dailyPresence, duration, allocation,
				comment, overTimePool);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllEmployees()
	 */
	@Override
	public List<Employee> getAllEmployees() throws RemoteException {
		return employeeService.getAllEmployees();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#createEmployee(java.lang.String,
	 * java.lang.String, java.lang.String, java.util.Calendar, java.lang.String,
	 * java.util.Calendar, ch.zbw.timeline.domain.Role, int, boolean)
	 */
	@Override
	public Employee createEmployee(String firstName, String lastName,
			String userName, Calendar commencementDate, String password,
			Calendar dateOfBirth, Role role, int employmentStatus,
			boolean active) throws RemoteException {
		return employeeService.createEmployee(firstName, lastName, userName,
				commencementDate, password, dateOfBirth, role, active,
				employmentStatus);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#generateMd5(java.lang.String)
	 */
	@Override
	public String generateMd5(String text) throws RemoteException {
		return securityService.generateMd5(text);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveEmployee(ch.zbw.timeline.domain
	 * .Employee)
	 */
	@Override
	public Employee saveEmployee(Employee employee) throws RemoteException {
		return employeeService.saveEmployee(employee);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllProcesses()
	 */
	@Override
	public List<Process> getAllProcesses() throws RemoteException {
		return taskProcessAllocationService.getAllProcesses();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveProcess(ch.zbw.timeline.domain
	 * .Process)
	 */
	@Override
	public Process saveProcess(Process process) {
		return taskProcessAllocationService.saveProcess(process);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#createProcess(java.lang.String,
	 * boolean)
	 */
	@Override
	public Process createProcess(String description, boolean active)
			throws RemoteException {
		return taskProcessAllocationService.createProcess(description, active);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveTask(ch.zbw.timeline.domain
	 * .Task)
	 */
	@Override
	public Task saveTask(Task task) throws RemoteException {
		return taskProcessAllocationService.saveTask(task);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#createTask(java.lang.String,
	 * boolean)
	 */
	@Override
	public Task createTask(String description, boolean active)
			throws RemoteException {
		return taskProcessAllocationService.createTask(description, active);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllTasks()
	 */
	@Override
	public List<Task> getAllTasks() throws RemoteException {
		return taskProcessAllocationService.getAllTasks();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveAllocation(ch.zbw.timeline.
	 * domain.Allocation)
	 */
	@Override
	public Allocation saveAllocation(Allocation allocation)
			throws RemoteException {
		return taskProcessAllocationService.saveAllocation(allocation);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#createAllocation(ch.zbw.timeline
	 * .domain.Process, ch.zbw.timeline.domain.Task, boolean)
	 */
	@Override
	public Allocation createAllocation(Process process, Task task,
			boolean active) throws RemoteException {
		return taskProcessAllocationService.createAllocation(task, process,
				active);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllAllocations()
	 */
	@Override
	public List<Allocation> getAllAllocations() throws RemoteException {
		return taskProcessAllocationService.getAllAllocations();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveHolidayFormula(ch.zbw.timeline
	 * .domain.HolidayFormula)
	 */
	@Override
	public HolidayFormula saveHolidayFormula(HolidayFormula holidayFormula)
			throws RemoteException {
		return holidayService.saveHolidayFormula(holidayFormula);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#createHolidayFormula(java.lang.
	 * String, java.lang.String)
	 */
	@Override
	public HolidayFormula createHolidayFormula(String description,
			String formula) throws RemoteException {
		return holidayService.createHolidayFormula(formula, description);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllHolidayFormulas()
	 */
	@Override
	public List<HolidayFormula> getAllHolidayFormulas() throws RemoteException {
		return holidayService.getAllHolidayFormulas();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveOverTimePool(ch.zbw.timeline
	 * .domain.OverTimePool)
	 */
	@Override
	public OverTimePool saveOverTimePool(OverTimePool overTimePool)
			throws RemoteException {
		return overTimePoolService.saveOverTimePool(overTimePool);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#createOverTimePool(ch.zbw.timeline
	 * .domain.Employee, double, java.lang.String)
	 */
	@Override
	public OverTimePool createOverTimePool(Employee employee,
			double numberOfHours, String description) throws RemoteException {
		return overTimePoolService.createOverTimePool(employee, numberOfHours,
				description);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllOverTimePools()
	 */
	@Override
	public List<OverTimePool> getAllOverTimePools() throws RemoteException {
		return overTimePoolService.getAllOverTimePools();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllLogEntries()
	 */
	@Override
	public List<LogEntry> getAllLogEntries() throws RemoteException {
		return logService.getAllLogEntries();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getAllYearConfigs()
	 */
	@Override
	public List<YearConfig> getAllYearConfigs() throws RemoteException {
		return yearConfigService.getAllYearConfigs();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveYearConfig(ch.zbw.timeline.
	 * domain.YearConfig)
	 */
	@Override
	public YearConfig saveYearConfig(YearConfig yearConfig)
			throws RemoteException {
		return yearConfigService.saveYearConfig(yearConfig);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#getOverTimePoolAllocations(ch.zbw
	 * .timeline.domain.Employee)
	 */
	@Override
	public List<Allocation> getOverTimePoolAllocations(Employee employee)
			throws RemoteException {
		return overTimePoolService.getOverTimePoolAllocations(employee);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#getOverTimePoolHoursUsed(ch.zbw
	 * .timeline.domain.Employee)
	 */
	@Override
	public double getOverTimePoolHoursUsed(Employee employee)
			throws RemoteException {
		return overTimePoolService.getOverTimePoolHoursUsed(employee);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveDailyPresence(ch.zbw.timeline
	 * .domain.DailyPresence)
	 */
	@Override
	public DailyPresence saveDailyPresence(DailyPresence dailyPresence)
			throws RemoteException {
		return dailyPresenceService.saveDailyPresence(dailyPresence);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#createDailyPresence(ch.zbw.timeline
	 * .domain.Employee, java.util.Calendar, java.util.Calendar,
	 * java.util.Calendar, java.util.Calendar, java.util.Calendar, boolean,
	 * boolean)
	 */
	@Override
	public DailyPresence createDailyPresence(Employee employee,
			Calendar dateOfPresence, Calendar morningStart,
			Calendar morningEnd, Calendar afternoonStart,
			Calendar afternoonEnd, boolean morningVacation,
			boolean afternoonVacation) {
		return dailyPresenceService.createDailyPresence(employee,
				dateOfPresence, morningStart, morningEnd, afternoonStart,
				afternoonEnd, morningVacation, afternoonVacation);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#getPresenceTimeTotal(ch.zbw.timeline
	 * .domain.DailyPresence)
	 */
	@Override
	public Time getPresenceTimeTotal(DailyPresence presence)
			throws RemoteException {
		return dailyPresenceService.getPresenceTimeTotal(presence);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#getPresenceTimeUnused(ch.zbw.timeline
	 * .domain.DailyPresence)
	 */
	@Override
	public Time getPresenceTimeUnused(DailyPresence presence)
			throws RemoteException {
		return dailyPresenceService.getPresenceTimeUnused(presence);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#getOverTimePool(ch.zbw.timeline
	 * .domain.Employee)
	 */
	@Override
	public OverTimePool getOverTimePool(Employee employee) {
		return overTimePoolService.getOverTimePool(employee);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#saveEntry(ch.zbw.timeline.domain
	 * .Entry)
	 */
	@Override
	public Entry saveEntry(Entry entry) throws RemoteException {
		return entryService.saveEntry(entry);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#deleteEntry(ch.zbw.timeline.domain
	 * .Entry)
	 */
	@Override
	public void deleteEntry(Entry entry) throws RemoteException {
		entryService.delete(entry);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#getPeriods(int)
	 */
	@Override
	public List<Period> getPeriods(int year) throws RemoteException {
		return yearConfigService.getAllPeriodsByYear(year);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ch.zbw.timeline.service.ServerService#generateStatistic(ch.zbw.timeline
	 * .domain.Employee, ch.zbw.timeline.domain.Period)
	 */
	@Override
	public Statistic generateStatistic(Employee employee, Period period)
			throws RemoteException {
		return statisticService.generateStatistic(employee, period);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.ServerService#isYearUsed(int)
	 */
	@Override
	public boolean isYearUsed(int yearConfigId) {
		return yearConfigService.isYearUsed(yearConfigId);
	}

}
